package com.demo.product.service;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 秒杀服务
 * 实现秒杀的核心业务逻辑
 */
@Service
public class SeckillService {

    private static final Logger log = LoggerFactory.getLogger(SeckillService.class);

    @Autowired
    private RedisLockService redisLockService;
    
    @Autowired
    private SeckillMessageService seckillMessageService;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    private static final String STOCK_PREFIX = "seckill:stock:";
    private static final String USER_LIMIT_PREFIX = "seckill:user:";
    private static final int LOCK_EXPIRE_TIME = 10; // 锁过期时间10秒
    private static final int USER_LIMIT_COUNT = 1; // 每个用户限购数量

    /**
     * 执行秒杀
     * @param userId 用户ID
     * @param productId 商品ID
     * @param quantity 购买数量
     * @return 秒杀结果
     */
    public Map<String, Object> doSeckill(Long userId, Long productId, Integer quantity) {
        Map<String, Object> result = new HashMap<>();
        
        // 参数校验
        if (userId == null || productId == null || quantity == null || quantity <= 0) {
            result.put("success", false);
            result.put("message", "参数错误");
            return result;
        }
        
        // 检查用户限购
        if (!checkUserLimit(userId, productId)) {
            result.put("success", false);
            result.put("message", "您已参与过该商品的秒杀活动");
            seckillMessageService.sendSeckillFailMessage(userId, productId, "用户重复参与");
            return result;
        }
        
        // 获取分布式锁
        String lockKey = "product:" + productId;
        String lockValue = redisLockService.tryLock(lockKey, LOCK_EXPIRE_TIME);
        
        if (lockValue == null) {
            result.put("success", false);
            result.put("message", "系统繁忙，请稍后重试");
            return result;
        }
        
        try {
            // 检查库存
            if (!checkAndReduceStock(productId, quantity)) {
                result.put("success", false);
                result.put("message", "商品库存不足");
                seckillMessageService.sendSeckillFailMessage(userId, productId, "库存不足");
                return result;
            }
            
            // 记录用户参与记录
            recordUserParticipation(userId, productId);
            
            // 发送订单消息到MQ
            seckillMessageService.sendSeckillOrderMessage(userId, productId, quantity);
            
            result.put("success", true);
            result.put("message", "秒杀成功，正在为您创建订单");
            
            log.info("秒杀成功，userId: {}, productId: {}, quantity: {}", userId, productId, quantity);
            
        } catch (Exception e) {
            log.error("秒杀处理异常，userId: {}, productId: {}", userId, productId, e);
            // 回滚库存
            rollbackStock(productId, quantity);
            result.put("success", false);
            result.put("message", "系统异常，请稍后重试");
        } finally {
            // 释放锁
            redisLockService.releaseLock(lockKey, lockValue);
        }
        
        return result;
    }

    /**
     * 检查用户限购
     * @param userId 用户ID
     * @param productId 商品ID
     * @return 是否可以参与
     */
    private boolean checkUserLimit(Long userId, Long productId) {
        String key = USER_LIMIT_PREFIX + productId + ":" + userId;
        try {
            return !Boolean.TRUE.equals(redisTemplate.hasKey(key));
        } catch (Exception e) {
            log.error("检查用户限购异常，userId: {}, productId: {}", userId, productId, e);
            return false;
        }
    }

    /**
     * 记录用户参与
     * @param userId 用户ID
     * @param productId 商品ID
     */
    private void recordUserParticipation(Long userId, Long productId) {
        String key = USER_LIMIT_PREFIX + productId + ":" + userId;
        try {
            redisTemplate.opsForValue().set(key, "1", 24, TimeUnit.HOURS);
        } catch (Exception e) {
            log.error("记录用户参与异常，userId: {}, productId: {}", userId, productId, e);
        }
    }

    /**
     * 检查并扣减库存
     * @param productId 商品ID
     * @param quantity 扣减数量
     * @return 是否成功
     */
    private boolean checkAndReduceStock(Long productId, Integer quantity) {
        String stockKey = STOCK_PREFIX + productId;
        try {
            Object stockObj = redisTemplate.opsForValue().get(stockKey);
            if (stockObj == null) {
                // 如果Redis中没有库存信息，可以从数据库加载
                log.warn("Redis中没有商品库存信息，productId: {}", productId);
                return false;
            }
            
            Integer currentStock = Integer.valueOf(stockObj.toString());
            if (currentStock < quantity) {
                log.warn("库存不足，productId: {}, currentStock: {}, requestQuantity: {}", 
                        productId, currentStock, quantity);
                return false;
            }
            
            // 扣减库存
            Long newStock = redisTemplate.opsForValue().decrement(stockKey, quantity);
            if (newStock < 0) {
                // 如果扣减后库存为负数，回滚
                redisTemplate.opsForValue().increment(stockKey, quantity);
                return false;
            }
            
            log.info("库存扣减成功，productId: {}, quantity: {}, remainStock: {}", 
                    productId, quantity, newStock);
            return true;
            
        } catch (Exception e) {
            log.error("检查扣减库存异常，productId: {}, quantity: {}", productId, quantity, e);
            return false;
        }
    }



    /**
     * 初始化商品库存到Redis
     * @param productId 商品ID
     * @param stock 库存数量
     */
    public void initStock(Long productId, Integer stock) {
        String stockKey = STOCK_PREFIX + productId;
        try {
            redisTemplate.opsForValue().set(stockKey, stock);
            log.info("初始化商品库存成功，productId: {}, stock: {}", productId, stock);
        } catch (Exception e) {
            log.error("初始化商品库存异常，productId: {}, stock: {}", productId, stock, e);
        }
    }

    /**
     * 获取当前库存
     * @param productId 商品ID
     * @return 当前库存
     */
    public Integer getCurrentStock(Long productId) {
        String stockKey = STOCK_PREFIX + productId;
        try {
            Object stockObj = redisTemplate.opsForValue().get(stockKey);
            return stockObj != null ? Integer.valueOf(stockObj.toString()) : 0;
        } catch (Exception e) {
            log.error("获取当前库存异常，productId: {}", productId, e);
            return 0;
        }
    }

    /**
     * 扣减库存（不使用分布式锁，用于订单服务调用）
     * @param productId 商品ID
     * @param quantity 扣减数量
     * @return 扣减是否成功
     */
    public boolean reduceStock(Long productId, Integer quantity) {
        String lockKey = "product:" + productId;
        String lockValue = redisLockService.tryLock(lockKey, LOCK_EXPIRE_TIME);
        
        if (lockValue == null) {
            log.warn("获取锁失败，productId: {}", productId);
            return false;
        }

        try {
            String stockKey = STOCK_PREFIX + productId;
            Object stockObj = redisTemplate.opsForValue().get(stockKey);
            
            if (stockObj == null) {
                log.warn("商品库存不存在，productId: {}", productId);
                return false;
            }
            
            int currentStock = Integer.valueOf(stockObj.toString());
            if (currentStock < quantity) {
                log.warn("库存不足，productId: {}, 当前库存: {}, 需要扣减: {}", productId, currentStock, quantity);
                return false;
            }
            
            // 扣减库存
            Long newStock = redisTemplate.opsForValue().decrement(stockKey, quantity);
            if (newStock < 0) {
                // 如果扣减后库存为负数，回滚
                redisTemplate.opsForValue().increment(stockKey, quantity);
                return false;
            }
            
            log.info("库存扣减成功，productId: {}, 扣减数量: {}, 剩余库存: {}", productId, quantity, newStock);
            return true;
            
        } catch (Exception e) {
            log.error("扣减库存异常，productId: {}, quantity: {}", productId, quantity, e);
            return false;
        } finally {
            // 释放锁
            redisLockService.releaseLock(lockKey, lockValue);
        }
    }

    /**
     * 回滚库存（公共方法）
     * @param productId 商品ID
     * @param quantity 回滚数量
     * @return 回滚是否成功
     */
    public boolean rollbackStock(Long productId, Integer quantity) {
        String lockKey = "product:" + productId;
        String lockValue = redisLockService.tryLock(lockKey, LOCK_EXPIRE_TIME);
        
        if (lockValue == null) {
            log.warn("获取锁失败，productId: {}", productId);
            return false;
        }

        try {
            String stockKey = STOCK_PREFIX + productId;
            redisTemplate.opsForValue().increment(stockKey, quantity);
            
            log.info("库存回滚成功，productId: {}, 回滚数量: {}", productId, quantity);
            return true;
            
        } catch (Exception e) {
            log.error("回滚库存异常，productId: {}, quantity: {}", productId, quantity, e);
            return false;
        } finally {
            // 释放锁
            redisLockService.releaseLock(lockKey, lockValue);
        }
    }
}